/*
 * tsk_adc.c
 *
 *  Created on: 21.03.2011
 *      Author: Meshkov Vladimir
 */

#include <string.h>
#include <stdint.h>
#include <stdio.h>

#if ADC_RMS == 1
#include <math.h>
#endif

#include <stm32f10x.h>

#include <FreeRTOS.h>
#include <task.h>
#include <queue.h>
#include "platform_config.h"

#include "tsk_adc.h"

#define stackDepth	(configMINIMAL_STACK_SIZE*2)
static portTASK_FUNCTION_PROTO( vTaskADC, pvParameters );
static void vInitInternalADC();
static void vInitExternalADC();

static EXTI_InitTypeDef 	EXTI_InitStructure;

//const uint8_t data_out[3] __attribute__((aligned(8))) = {0xAA, 0xAA, 0xAA};
uint8_t data_in[3] __attribute__((aligned(8))) = {0x00, 0x00, 0x00};

volatile uint16_t ADC1_Data = 0;
volatile uint16_t ADC2_Data = 0;
volatile uint16_t ADC3_Data = 0;

uint16_t ADC_ConvertedValue[ADC_DMA_SIZE*ADC_NUM_SAMPLES] __attribute__((aligned(8)));

#define BUFFER_SIZE	8
//int32_t buffer_in[BUFFER_SIZE];
//uint8_t buffer_count = 0;

static void _delay_ms( int ms )
{
int i;
	for( ; ms > 0; ms-- )
		for( i = 200; i > 0; i-- )
			asm volatile ("nop");
}

void vStartADC( unsigned portBASE_TYPE uxPriority )
{
	vInitInternalADC();
	vInitExternalADC();

	xTaskCreate( vTaskADC, (signed portCHAR *)"ADC", stackDepth, NULL, uxPriority, NULL);
}

static void vInitInternalADC()
{
GPIO_InitTypeDef 	GPIO_InitStructure;
ADC_InitTypeDef		ADC_InitStructure;
DMA_InitTypeDef		DMA_InitStructure;
NVIC_InitTypeDef	NVIC_InitStructure;

	RCC_ADCCLKConfig( RCC_PCLK2_Div8 );
	RCC_APB2PeriphClockCmd( RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOA, ENABLE );
	RCC_AHBPeriphClockCmd( RCC_AHBPeriph_DMA1, ENABLE );

	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
	GPIO_Init( GPIOA, &GPIO_InitStructure );

	DMA_DeInit( DMA1_Channel1 );
	DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address;
	DMA_InitStructure.DMA_MemoryBaseAddr = ( uint32_t ) &ADC_ConvertedValue[0];
	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
	DMA_InitStructure.DMA_BufferSize = ADC_DMA_SIZE*ADC_NUM_SAMPLES;
	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
	DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
	DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
	DMA_InitStructure.DMA_Priority = DMA_Priority_Low;
	DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
	DMA_Init( DMA1_Channel1, &DMA_InitStructure );
	DMA_ITConfig( DMA1_Channel1, DMA_IT_HT | DMA_IT_TC, ENABLE );
	DMA_Cmd( DMA1_Channel1, ENABLE );

	NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel1_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x00;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x00;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init( &NVIC_InitStructure );

	ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
	ADC_InitStructure.ADC_ScanConvMode = ENABLE;
	ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
	ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
	ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
	ADC_InitStructure.ADC_NbrOfChannel = 3;
	ADC_Init( ADC1, &ADC_InitStructure );

	ADC_TempSensorVrefintCmd( ENABLE );

	ADC_RegularChannelConfig( ADC1, ADC_Channel_7, 1, ADC_SampleTime_239Cycles5 );
	ADC_RegularChannelConfig( ADC1, ADC_Channel_6, 2, ADC_SampleTime_239Cycles5 );
	ADC_RegularChannelConfig( ADC1, ADC_Channel_16, 3, ADC_SampleTime_239Cycles5 );

	ADC_Cmd( ADC1, ENABLE );
	ADC_ResetCalibration( ADC1 );
	while( ADC_GetCalibrationStatus( ADC1 ) );
	ADC_StartCalibration( ADC1 );
	while( ADC_GetCalibrationStatus( ADC1 ) );
	ADC_DMACmd( ADC1, ENABLE );
	ADC_SoftwareStartConvCmd( ADC1, ENABLE );
}

/**
 * Пуск ADS1225 с автокалибровкой.
 */
static void vInitExternalADC()
{
GPIO_InitTypeDef 	GPIO_InitStructure;
SPI_InitTypeDef		SPI_InitStructure;

	GPIO_InitStructure.GPIO_Pin		= ADS_DOUT_PIN;
	GPIO_InitStructure.GPIO_Mode	= GPIO_Mode_IN_FLOATING;
	GPIO_InitStructure.GPIO_Speed	= GPIO_Speed_50MHz;
	GPIO_Init( ADS_PORT, &GPIO_InitStructure );

	GPIO_InitStructure.GPIO_Pin		= ADS_SCLK_PIN;
	GPIO_InitStructure.GPIO_Mode	= GPIO_Mode_Out_PP;
	GPIO_Init( ADS_PORT, &GPIO_InitStructure );
	GPIO_ResetBits( ADS_PORT, ADS_SCLK_PIN );

	GPIO_InitStructure.GPIO_Pin		= ADS_START_PIN;
	GPIO_InitStructure.GPIO_Mode	= GPIO_Mode_Out_PP;
	GPIO_Init( ADS_PORT, &GPIO_InitStructure );
	GPIO_ResetBits( ADS_PORT, ADS_START_PIN );

	GPIO_EXTILineConfig( GPIO_PortSourceGPIOB, GPIO_PinSource14 );
	GPIO_SetBits( ADS_PORT, ADS_START_PIN );

	// Self-calibration. Send 26 pulses
int i;
	for(i = 0; i < 26; i++ )
	{
		GPIO_SetBits( ADS_PORT, ADS_SCLK_PIN );
		_delay_ms( 1 );
		GPIO_ResetBits( ADS_PORT, ADS_SCLK_PIN );
		_delay_ms( 1 );
	}
	//GPIO_ResetBits( ADS_PORT, ADS_START_PIN );

	EXTI_InitStructure.EXTI_Line	= EXTI_Line14;
	EXTI_InitStructure.EXTI_Mode	= EXTI_Mode_Interrupt;
	EXTI_InitStructure.EXTI_Trigger	= EXTI_Trigger_Falling;
	EXTI_InitStructure.EXTI_LineCmd	= ENABLE;
	EXTI_Init( &EXTI_InitStructure );

	RCC_APB1PeriphClockCmd( RCC_APB1Periph_SPI2, ENABLE );

	SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
	SPI_InitStructure.SPI_Mode		= SPI_Mode_Master;
	SPI_InitStructure.SPI_DataSize	= SPI_DataSize_8b;
	SPI_InitStructure.SPI_CPOL		= SPI_CPOL_Low;
	SPI_InitStructure.SPI_CPHA		= SPI_CPHA_2Edge;
	SPI_InitStructure.SPI_NSS		= SPI_NSS_Soft;
	SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_64;
	SPI_InitStructure.SPI_FirstBit	= SPI_FirstBit_MSB;
	SPI_InitStructure.SPI_CRCPolynomial = 7;
	SPI_Init( SPI2, &SPI_InitStructure );

	SPI_Cmd( SPI2, DISABLE );
}


portTASK_FUNCTION( vTaskADC, pvParameters )
{
(void)pvParameters;

	for(;;)
	{
		vTaskDelay(1000);
	}
}

/*******************************************************************************
* Function Name  : DMA1_Channel1_IRQHandler
* Description    : This function handles DMA1 Channel 1 interrupt request.
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
void DMA1_Channel1_IRQHandler(void)
{
uint32_t i;
uint64_t dat1, dat2, dat3;

	if( DMA_GetITStatus( DMA1_IT_HT1 ) )
	{

#if ADC_RMS == 1
		// Считем среднеквадратичное отклонение
		dat1 = 0; dat2 = 0; dat3 = 0;

		for( i = 0; i < ADC_DMA_SIZE * ADC_NUM_SAMPLES / 2; i += 3 )
		{
			dat1 += ADC_ConvertedValue[i+0] * ADC_ConvertedValue[i+0];
			dat2 += ADC_ConvertedValue[i+1] * ADC_ConvertedValue[i+1];
			dat3 += ADC_ConvertedValue[i+2] * ADC_ConvertedValue[i+2];
		}
		dat1 /=  ( ADC_DMA_SIZE * ADC_NUM_SAMPLES / 6 );
		dat2 /=  ( ADC_DMA_SIZE * ADC_NUM_SAMPLES / 6 );
		dat3 /=  ( ADC_DMA_SIZE * ADC_NUM_SAMPLES / 6 );

		portENTER_CRITICAL();
			ADC1_Data = ( uint16_t ) sqrt( ( double ) dat1 );
			ADC2_Data = ( uint16_t ) sqrt( ( double ) dat2 );
			ADC3_Data = ( uint16_t ) sqrt( ( double ) dat3 );
		portEXIT_CRITICAL();
#else

		// Считаем простое учреднение
		dat1 = 0;
		dat2 = 0;
		dat3 = 0;
		for( i = 0; i < ADC_DMA_SIZE * ADC_NUM_SAMPLES / 2; i += 3 )
		{
			dat1 += ADC_ConvertedValue[i];
			dat2 += ADC_ConvertedValue[i+1];
			dat3 += ADC_ConvertedValue[i+2];
		}
		dat1 = dat1 / ( ADC_DMA_SIZE * ADC_NUM_SAMPLES / 6 );
		dat2 = dat2 / ( ADC_DMA_SIZE * ADC_NUM_SAMPLES / 6 );
		dat3 = dat3 / ( ADC_DMA_SIZE * ADC_NUM_SAMPLES / 6 );

		portENTER_CRITICAL();
			ADC1_Data = dat1;
			ADC2_Data = dat2;
			ADC3_Data = dat3;
		portEXIT_CRITICAL();
#endif

		DMA_ClearITPendingBit( DMA1_IT_HT1 );
	}

	if( DMA_GetITStatus( DMA1_IT_TC1 ) )
	{
#if ADC_RMS == 1
		// Считем среднеквадратичное отклонение
		dat1 = 0; dat2 = 0; dat3 = 0;

		for( i = ADC_DMA_SIZE * ADC_NUM_SAMPLES / 2; i < ADC_DMA_SIZE * ADC_NUM_SAMPLES; i += 3 )
		{
			dat1 += ADC_ConvertedValue[i+0] * ADC_ConvertedValue[i+0];
			dat2 += ADC_ConvertedValue[i+1] * ADC_ConvertedValue[i+1];
			dat3 += ADC_ConvertedValue[i+2] * ADC_ConvertedValue[i+2];
		}
		dat1 /= ( ADC_DMA_SIZE * ADC_NUM_SAMPLES / 6 );
		dat2 /= ( ADC_DMA_SIZE * ADC_NUM_SAMPLES / 6 );
		dat3 /= ( ADC_DMA_SIZE * ADC_NUM_SAMPLES / 6 );

		portENTER_CRITICAL();
			ADC1_Data = ( uint16_t ) sqrt( ( double ) dat1 );
			ADC2_Data = ( uint16_t ) sqrt( ( double ) dat2 );
			ADC3_Data = ( uint16_t ) sqrt( ( double ) dat3 );
		portEXIT_CRITICAL();
#else
		// Считаем простое учреднение
		dat1 = 0;
		dat2 = 0;
		dat3 = 0;
		for( i = ADC_DMA_SIZE * ADC_NUM_SAMPLES / 2; i < ADC_DMA_SIZE * ADC_NUM_SAMPLES; i += 3 )
		{
			dat1 += ADC_ConvertedValue[i];
			dat2 += ADC_ConvertedValue[i+1];
			dat3 += ADC_ConvertedValue[i+2];
		}
		dat1 = dat1 / ( ADC_DMA_SIZE * ADC_NUM_SAMPLES / 6 );
		dat2 = dat2 / ( ADC_DMA_SIZE * ADC_NUM_SAMPLES / 6 );
		dat3 = dat3 / ( ADC_DMA_SIZE * ADC_NUM_SAMPLES / 6 );

		portENTER_CRITICAL();
			ADC1_Data = dat1;
			ADC2_Data = dat2;
			ADC3_Data = dat3;
		portEXIT_CRITICAL();
#endif

		DMA_ClearITPendingBit( DMA1_IT_TC1 );
	}
}


void EXTI15_10_IRQHandler(void)
{
uint8_t i;
int32_t dat = 0;
GPIO_InitTypeDef 	GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

	if( EXTI_GetITStatus( EXTI_Line13 ) )
	{
		// Сбросим таймер по изменению состояния кнопки
		TIM_SetCounter( TIM7, 0 );
		EXTI_ClearITPendingBit( EXTI_Line13 );
	}


	if( EXTI_GetITStatus( EXTI_Line14 ) != RESET )
	{
		// Отключить прерывание и считать 3 байта данных.
		EXTI_InitStructure.EXTI_LineCmd = DISABLE;
		EXTI_Init( &EXTI_InitStructure );
		EXTI_ClearITPendingBit( EXTI_Line14 );

		GPIO_InitStructure.GPIO_Pin 	= ADS_DOUT_PIN | ADS_SCLK_PIN;
		GPIO_InitStructure.GPIO_Mode 	= GPIO_Mode_AF_PP;
		GPIO_Init( ADS_PORT, &GPIO_InitStructure );
		SPI_Cmd( SPI2, ENABLE );

		for( i = 0; i < 3; i++ )
		{
			while( SPI_I2S_GetFlagStatus( SPI2, SPI_I2S_FLAG_TXE ) == RESET );
			SPI_I2S_SendData( SPI2, 0x00AA );
			while( SPI_I2S_GetFlagStatus( SPI2, SPI_I2S_FLAG_RXNE ) == RESET );
			data_in[i] = SPI_I2S_ReceiveData( SPI2 );
		}
		SPI_Cmd( SPI2, DISABLE );

		dat = 0;
		dat = (data_in[0] << 16) ;
		dat |= (data_in[1] << 8);
		dat |= (data_in[2] << 0);
#ifdef DEBUG
//		printf( "ADC %0X\n", ( unsigned int ) dat );
#endif
//		data_summ += dat;
//		buffer_count++;
//		if( buffer_count > BUFFER_SIZE )
//		{
//			data_summ /= buffer_count;
//			char out_buffer[20];
//			memset( out_buffer, 0, 20 );
//			sprintf( out_buffer, "%0X\n", (int)data_summ );
//			data_summ = 0;
//			buffer_count = 0;
//			hd44780_outcmd( HD44780_DDADDR(0x40) );
//			_delay_ms(10);
//			DrawString( out_buffer );
//
//		}

		GPIO_InitStructure.GPIO_Pin 	= ADS_DOUT_PIN | ADS_SCLK_PIN;
		GPIO_InitStructure.GPIO_Mode 	= GPIO_Mode_IN_FLOATING;
		GPIO_Init( ADS_PORT, &GPIO_InitStructure );
		EXTI_InitStructure.EXTI_LineCmd = ENABLE;
		EXTI_Init( &EXTI_InitStructure );

	}
}

